#include "stm32f4xx.h"
#include "board.h"
#include "stm32f4xx_adc.h"

#ifndef ADC_CR2_CAL
    #define ADC_CR2_CAL            ((uint32_t)0x00000004)  // 校准使能位
    #define ADC_CR2_RSTCAL         ((uint32_t)0x00000008)  // 校准重置位
#endif

#define         AD_GPIO_PORT        GPIOB
#define         AD_GPIO_Pin         GPIO_Pin_1
#define         MQ2_GPIO_PORT       GPIOC
#define         MQ2_GPIO_Pin        GPIO_Pin_1

// 重置ADC校准（等效于ADC_ResetCalibration）
static void reset_adc_calibration(ADC_TypeDef* ADCx)
{
    ADCx->CR2 |= ADC_CR2_RSTCAL;
}

// 检查ADC校准重置状态（等效于ADC_GetResetCalibrationStatus）
static FlagStatus get_adc_reset_calibration_status(ADC_TypeDef* ADCx)
{
    return (ADCx->CR2 & ADC_CR2_RSTCAL) ? SET : RESET;
}

// 开始ADC校准（等效于ADC_StartCalibration）
static void start_adc_calibration(ADC_TypeDef* ADCx)
{
    ADCx->CR2 |= ADC_CR2_CAL;
}

// 检查ADC校准状态（等效于ADC_GetCalibrationStatus）
static FlagStatus get_adc_calibration_status(ADC_TypeDef* ADCx)
{
    return (ADCx->CR2 & ADC_CR2_CAL) ? SET : RESET;
}

void ad_init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin = AD_GPIO_Pin;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(AD_GPIO_PORT, &GPIO_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_56Cycles);

    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 数据右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;   // 触发规则组通道转换的外部事件
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //不使用外部事件
    ADC_InitStructure.ADC_NbrOfConversion = 1;  // 转换次数
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;   //单次扫描，只扫描一个通道
    ADC_Init(ADC1, &ADC_InitStructure);

    /* ADC校准 */
    ADC_Cmd(ADC1, ENABLE);
    reset_adc_calibration(ADC1);
    while(get_adc_reset_calibration_status(ADC1) == SET);
    start_adc_calibration(ADC1);
    while(get_adc_calibration_status(ADC1) == SET);
}

void mq2_ad_init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Pin = MQ2_GPIO_Pin;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MQ2_GPIO_PORT, &GPIO_InitStructure);

    ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_480Cycles);

    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 数据右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;   // 触发规则组通道转换的外部事件
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //不使用外部事件
    ADC_InitStructure.ADC_NbrOfConversion = 1;  // 转换次数
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;   //单次扫描，只扫描一个通道
    ADC_Init(ADC3, &ADC_InitStructure);

    /* ADC校准 */
    ADC_Cmd(ADC3, ENABLE);
    reset_adc_calibration(ADC3);
    while(get_adc_reset_calibration_status(ADC3) == SET);
    start_adc_calibration(ADC3);
    while(get_adc_calibration_status(ADC3) == SET);
}

void mq2_ad_deinit(void)
{
    ADC_Cmd(ADC3, DISABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, DISABLE);
}

void ad_deinit(void)
{
    ADC_Cmd(ADC1, DISABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);
}

// 获取MQ2传感器的ADC值
uint16_t mq2_get_value(void)
{
    ADC_SoftwareStartConv(ADC3);
    while(ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET);
    return ADC_GetConversionValue(ADC3);
}

// 获取太阳能板发电电压值
uint16_t adc_get_value(void)
{
    ADC_SoftwareStartConv(ADC1);
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    return ADC_GetConversionValue(ADC1);
}
